use crate::error::{ApiError, ApiResult};
use crate::models::{CreateUserRequest, UpdateUserRequest, User};
use axum::{
    extract::{Path, State},
    http::StatusCode,
    Json,
};
use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use std::sync::Arc;

#[derive(Debug, Deserialize)]
pub struct ListUsersQuery {
    #[serde(default)]
    pub page: i64,
    #[serde(default = "default_page_size")]
    pub page_size: i64,
    pub search: Option<String>,
}

fn default_page_size() -> i64 {
    20
}

#[derive(Debug, Serialize)]
pub struct ListUsersResponse {
    pub users: Vec<User>,
    pub total: i64,
    pub page: i64,
    pub page_size: i64,
}

pub async fn list_users(
    State(pool): State<Arc<SqlitePool>>,
) -> ApiResult<Json<ListUsersResponse>> {
    let users = sqlx::query_as::<_, User>("SELECT * FROM users ORDER BY id DESC LIMIT 20")
        .fetch_all(pool.as_ref())
        .await?;

    let total: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users")
        .fetch_one(pool.as_ref())
        .await?;

    Ok(Json(ListUsersResponse {
        users,
        total: total.0,
        page: 0,
        page_size: 20,
    }))
}

pub async fn create_user(
    State(pool): State<Arc<SqlitePool>>,
    Json(req): Json<CreateUserRequest>,
) -> ApiResult<(StatusCode, Json<User>)> {
    // Check if user exists
    let exists: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users WHERE username = ?")
        .bind(&req.username)
        .fetch_one(pool.as_ref())
        .await?;

    if exists.0 > 0 {
        return Err(ApiError::UserAlreadyExists);
    }

    // Create user
    let result = sqlx::query(
        "INSERT INTO users (username, password, max_bandwidth_up, max_bandwidth_down, traffic_limit, expire_at) 
         VALUES (?, ?, ?, ?, ?, ?)"
    )
    .bind(&req.username)
    .bind(&req.password)
    .bind(req.max_bandwidth_up)
    .bind(req.max_bandwidth_down)
    .bind(req.traffic_limit)
    .bind(req.expire_at)
    .execute(pool.as_ref())
    .await?;

    let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = ?")
        .bind(result.last_insert_rowid())
        .fetch_one(pool.as_ref())
        .await?;

    Ok((StatusCode::CREATED, Json(user)))
}

pub async fn get_user(
    State(pool): State<Arc<SqlitePool>>,
    Path(id): Path<i64>,
) -> ApiResult<Json<User>> {
    let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = ?")
        .bind(id)
        .fetch_optional(pool.as_ref())
        .await?
        .ok_or(ApiError::UserNotFound)?;

    Ok(Json(user))
}

pub async fn delete_user(
    State(pool): State<Arc<SqlitePool>>,
    Path(id): Path<i64>,
) -> ApiResult<StatusCode> {
    let result = sqlx::query("DELETE FROM users WHERE id = ?")
        .bind(id)
        .execute(pool.as_ref())
        .await?;

    if result.rows_affected() == 0 {
        return Err(ApiError::UserNotFound);
    }

    Ok(StatusCode::NO_CONTENT)
}
